﻿using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DynamicApiController;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FurStudy.Application
{
    /// <summary>
    /// 存储过程使用
    /// 注：Furion框架每一个数据库操作都支持异步方式
    /// </summary>
    [DynamicApiController]
    public class SqlService
    {
        // 初始化方式

        // 注入
        // 方式一：ISqlRepository
        private ISqlRepository _sqlRepository;

        // 方式二：ISqlExecuteProxy
        private ISqlExecuteProxy _sqlExecuteProxy;

        // 方式三：实体仓储方式
        // var persons = personRepository.SqlProcedureQuery("proc_GetPersons");

        // 方式四：字符串拓展方式
        // var persons = "proc_GetPersons".SqlProcedureQuery();

        // 构造
        public SqlService(ISqlRepository sqlRepository, ISqlExecuteProxy sqlExecuteProxy)
        {
            _sqlRepository = sqlRepository;
            _sqlExecuteProxy = sqlExecuteProxy;
        }

        public void ReturnValue()
        {
            #region 返回DataTable

            // ISqlRepository方法
            var dataTable = _sqlRepository.SqlProcedureQuery("proc_GetPersons");

            //// ISqlDispatchProxy 方式
            //var dataTable = _sqlExecuteProxy.GetPersons();  // 推荐方式

            //// 实体仓储方式
            //var dataTable = _personRepository.SqlProcedureQuery("proc_GetPersons");

            //// IRepository 非泛型方式
            //var dataTable = _repository.Sql().SqlProcedureQuery("proc_GetPersons");

            //// 变态懒人方式，直接通过存储过程名执行
            //var dataTable = "proc_GetPersons".SqlProcedureQuery();

            #endregion

            #region 返回DataSet

            // ISqlRepository方法
            var dataSet = _sqlRepository.SqlProcedureQueries("proc_GetPersons");

            //// ISqlDispatchProxy 方式
            //var dataSet = _sqlExecuteProxy.GetPersons();  // 推荐方式

            //// 实体仓储方式
            //var dataSet = _personRepository.SqlProcedureQueries("proc_GetPersons");

            //// IRepository 非泛型方式
            //var dataSet = _repository.Sql().SqlProcedureQueries("proc_GetPersons");

            //// 变态懒人方式，直接通过存储过程名执行
            //var dataSet = "proc_GetPersons".SqlProcedureQueries();

            #endregion

            #region 返回List<T>

            // ISqlRepository 方法
            var list = _sqlRepository.SqlProcedureQuery<Person>("proc_GetPersons");

            //// ISqlDispatchProxy 方式
            //var list = _sqlExecuteProxy.GetPersons();  // 推荐方式

            //// 实体仓储方式
            //var list = _personRepository.SqlProcedureQuery<Person>("proc_GetPersons");

            //// IRepository 非泛型方式
            //var list = _repository.Sql().SqlProcedureQuery<Person>("proc_GetPersons");

            //// 变态懒人方式，直接通过存储过程名执行
            //var list = "proc_GetPersons".SqlProcedureQuery<Person>();

            #endregion

            #region 返回 Tuple<T1,...T8>

            // ISqlRepository 方法

            // 返回一个结果集
            var list1 = _sqlRepository.SqlProcedureQueries<Person>("proc_GetPersons");

            //// 返回两个结果集
            //var (list1, list2) = _sqlRepository.SqlProcedureQueries<T1, T2>("proc_GetPersons");

            //// 返回三个结果集
            //var (list1, list2, list3) = _sqlRepository.SqlProcedureQueries<T1, T2, T3>("proc_GetPersons");

            //// 返回四个结果集
            //var (list1, list2, list3, list4) = _sqlRepository.SqlProcedureQueries<T1, T2, T3, T4>("proc_GetPersons");

            //// 返回五个结果集
            //var (list1, list2, list3, list4, list5) = _sqlRepository.SqlProcedureQueries<T1, T2, T3, T4, T5>("proc_GetPersons");

            //// 返回六个结果集
            //var (list1, list2, list3, list4, list5, list6) = _sqlRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6>("proc_GetPersons");

            //// 返回七个结果集
            //var (list1, list2, list3, list4, list5, list6, list7) = _sqlRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7>("proc_GetPersons");

            //// 返回八个结果集
            //var (list1, list2, list3, list4, list5, list6, list7, list8) = _sqlRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7, T8>("proc_GetPersons");

            // ==================================

            // ISqlDispatchProxy 方式，推荐方式，自动处理多个结果集

            //// 返回一个结果集
            //var list1 = _sqlRepository.GetDatas();

            //// 返回两个结果集
            //var (list1, list2) = _sqlRepository.GetDatas();

            //// 返回三个结果集
            //var (list1, list2, list3) = _sqlRepository.GetDatas();

            //// 返回四个结果集
            //var (list1, list2, list3, list4) = _sqlRepository.GetDatas();

            //// 返回五个结果集
            //var (list1, list2, list3, list4, list5) = _sqlRepository.GetDatas();

            //// 返回六个结果集
            //var (list1, list2, list3, list4, list5, list6) = _sqlRepository.GetDatas();

            //// 返回七个结果集
            //var (list1, list2, list3, list4, list5, list6, list7) = _sqlRepository.GetDatas();

            //// 返回八个结果集
            //var (list1, list2, list3, list4, list5, list6, list7, list8) = _sqlRepository.GetDatas();

            // ==================================

            // 实体仓储方式

            //// 返回一个结果集
            //var list1 = _personRepository.SqlProcedureQueries<T1>("proc_GetPersons");

            //// 返回两个结果集
            //var (list1, list2) = _personRepository.SqlProcedureQueries<T1, T2>("proc_GetPersons");

            //// 返回三个结果集
            //var (list1, list2, list3) = _personRepository.SqlProcedureQueries<T1, T2, T3>("proc_GetPersons");

            //// 返回四个结果集
            //var (list1, list2, list3, list4) = _personRepository.SqlProcedureQueries<T1, T2, T3, T4>("proc_GetPersons");

            //// 返回五个结果集
            //var (list1, list2, list3, list4, list5) = _personRepository.SqlProcedureQueries<T1, T2, T3, T4, T5>("proc_GetPersons");

            //// 返回六个结果集
            //var (list1, list2, list3, list4, list5, list6) = _personRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6>("proc_GetPersons");

            //// 返回七个结果集
            //var (list1, list2, list3, list4, list5, list6, list7) = _personRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7>("proc_GetPersons");

            //// 返回八个结果集
            //var (list1, list2, list3, list4, list5, list6, list7, list8) = _personRepository.SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7, T8>("proc_GetPersons");

            // ==================================

            // IRepository 非泛型方式

            //// 返回一个结果集
            //var list1 = _repository.Sql().SqlProcedureQueries<T1>("proc_GetPersons");

            //// 返回两个结果集
            //var (list1, list2) = _repository.Sql().SqlProcedureQueries<T1, T2>("proc_GetPersons");

            //// 返回三个结果集
            //var (list1, list2, list3) = _repository.Sql().SqlProcedureQueries<T1, T2, T3>("proc_GetPersons");

            //// 返回四个结果集
            //var (list1, list2, list3, list4) = _repository.Sql().SqlProcedureQueries<T1, T2, T3, T4>("proc_GetPersons");

            //// 返回五个结果集
            //var (list1, list2, list3, list4, list5) = _repository.Sql().SqlProcedureQueries<T1, T2, T3, T4, T5>("proc_GetPersons");

            //// 返回六个结果集
            //var (list1, list2, list3, list4, list5, list6) = _repository.Sql().SqlProcedureQueries<T1, T2, T3, T4, T5, T6>("proc_GetPersons");

            //// 返回七个结果集
            //var (list1, list2, list3, list4, list5, list6, list7) = _repository.Sql().SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7>("proc_GetPersons");

            //// 返回八个结果集
            //var (list1, list2, list3, list4, list5, list6, list7, list8) = _repository.Sql().SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7, T8>("proc_GetPersons");

            // ==================================

            // 变态懒人方式，直接通过存储过程名执行

            //// 返回一个结果集
            //var list1 = "proc_GetPersons".SqlProcedureQueries<T1>();

            //// 返回两个结果集
            //var (list1, list2) = "proc_GetPersons".SqlProcedureQueries<T1, T2>();

            //// 返回三个结果集
            //var (list1, list2, list3) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3>();

            //// 返回四个结果集
            //var (list1, list2, list3, list4) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3, T4>();

            //// 返回五个结果集
            //var (list1, list2, list3, list4, list5) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3, T4, T5>();

            //// 返回六个结果集
            //var (list1, list2, list3, list4, list5, list6) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3, T4, T5, T6>();

            //// 返回七个结果集
            //var (list1, list2, list3, list4, list5, list6, list7) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7>();

            //// 返回八个结果集
            //var (list1, list2, list3, list4, list5, list6, list7, list8) = "proc_GetPersons".SqlProcedureQueries<T1, T2, T3, T4, T5, T6, T7, T8>();

            #endregion

            #region 返回单行单列object

            // ISqlRepository方式
            var value = _sqlRepository.SqlProcedureScalar("proc_GetName");

            //// ISqlDispatchProxy 方式
            //var value = _sqlExecuteProxy.GetName();  // 推荐方式

            //// 实体仓储方式
            //var value = _personRepository.SqlProcedureScalar("proc_GetName");

            //// IRepository 非泛型方式
            //var value = _repository.Sql().SqlProcedureScalar("proc_GetName");

            // 变态懒人方式，直接通过存储过程名执行
            var value2 = "proc_GetName".SqlProcedureScalar();

            #endregion

            #region 返回单行单列<T>

            // ISqlRepository方式
            var t_value = _sqlRepository.SqlProcedureScalar<string>("proc_GetName");

            //// ISqlDispatchProxy 方式
            //var t_value = _sqlExecuteProxy.GetName();  // 推荐方式

            //// 实体仓储方式
            //var t_value = _personRepository.SqlProcedureScalar<string>("proc_GetName");

            //// IRepository 非泛型方式
            //var t_value = _repository.Sql().SqlProcedureScalar<string>("proc_GetName");

            // 变态懒人方式，直接通过存储过程名执行
            var t_value2 = "proc_GetName".SqlProcedureScalar<string>();

            #endregion

            #region 执行但无返回

            // ISqlRepository方式
            _sqlRepository.SqlProcedureNonQuery("proc_UpdateData");

            //// ISqlDispatchProxy 方式
            //_sqlExecuteProxy.UpdateData();  // 推荐方式

            //// 实体仓储方式
            //_personRepository.SqlProcedureNonQuery("proc_UpdateData");

            //// IRepository 非泛型方式
            //_repository.Sql().SqlProcedureNonQuery("proc_UpdateData");

            // 变态懒人方式，直接通过存储过程名执行
            "proc_UpdateData".SqlProcedureNonQuery();

            #endregion

            #region 执行复杂存储过程

            // 在存储过程中，有一种例子非常复杂，那就是既有INPUT参数，又有OUTPUT参数，还有RETURN参数，同时还输出结果集💥

            //CREATE PROC PROC_Output
            //@Id INT,    // 输入参数
            //@Name NVARCHAR(32) OUTPUT,  // 输出参数，还带长度
            //@Age INT OUTPUT // 输出参数
            //AS
            //BEGIN
            //    SET @Name = 'Furion Output';

            //// 输出结果集
            //SELECT*
            //FROM dbo.Test
            //WHERE Id > @Id;

            //// 输出结果集
            //SELECT TOP 10
            //       *
            //FROM dbo.Test;

            //SET @Age = 27;

            //// 带 RETURN 返回
            //RETURN 10;
            //END;

            #endregion

            #region 创建参数模型

            // 见下方ProcOutputModel类

            #endregion

            #region 执行复杂存储过程

            #region DataSet方式

            // ISqlRepository 方法
            ProcedureOutputResult result = _sqlRepository.SqlProcedureOutput("proc_Complex", new ProcOutputModel { });

            //// ISqlDispatchProxy 方式
            //ProcedureOutputResult result = _sqlExecuteProxy.Complex(new ProcOutputModel { });  // 推荐方式

            //// 实体仓储方式
            //ProcedureOutputResult result = _personRepository.SqlProcedureOutput("proc_Complex", new ProcOutputModel { });

            //// IRepository 非泛型方式
            //ProcedureOutputResult result = _repository.Sql().SqlProcedureOutput("proc_Complex", new ProcOutputModel { });

            // 变态懒人方式，直接通过存储过程名执行
            ProcedureOutputResult result2 = "proc_Complex".SqlProcedureOutput(new ProcOutputModel { });

            // 获取 OUTPUT 参数值
            var outputs = result.OutputValues;

            // 获取 RETURN 返回值
            var reval = result.ReturnValue;

            // 获取返回结果集
            var dataSet1 = result.Result;

            #endregion

            #region Tuple<T1,...T8> 方式

            //// ISqlRepository 方法
            //ProcedureOutputResult<(List<Test>, List<Test>)> result = _sqlRepository.SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel { });

            //// ISqlDispatchProxy 方式
            //ProcedureOutputResult<(List<Test>, List<Test>)> result = _sqlExecuteProxy.Complex(new ProcOutputModel { });  // 推荐方式

            //// 实体仓储方式
            //ProcedureOutputResult<(List<Test>, List<Test>)> result = _personRepository.SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel { });

            //// IRepository 非泛型方式
            //ProcedureOutputResult<(List<Test>, List<Test>)> result = _repository.Sql().SqlProcedureOutput<(List<Test>, List<Test>)>("proc_Complex", new ProcOutputModel { });

            //// 变态懒人方式，直接通过存储过程名执行
            //ProcedureOutputResult<(List<Test>, List<Test>)> result = "proc_Complex".SqlProcedureOutput<(List<Test>, List<Test>)>(new ProcOutputModel { });

            // 获取 OUTPUT 参数值
            var outputs2 = result.OutputValues;

            // 获取 RETURN 返回值
            var reval2 = result.ReturnValue;

            // 获取返回结果集
            //var (list1, list2) = result.Result;

            #endregion

            #endregion
        }

        /// <summary>
        /// 参数模型
        /// </summary>
        public class ProcOutputModel
        {
            public int Id { get; set; } // 输入参数

            [DbParameter(ParameterDirection.Output, Size = 32)]
            public string Name { get; set; }    // 输出参数

            [DbParameter(ParameterDirection.Output)]
            public int Age { get; set; }    // 输出参数

            [DbParameter(ParameterDirection.ReturnValue)]
            public int ReturnValue { get; set; }    // 返回值
        }
    }
}
